package org.chen.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.paypal.core.PayPalHttpClient;
import com.paypal.http.HttpResponse;
import com.paypal.orders.Order;
import com.paypal.orders.OrdersGetRequest;
import com.paypal.payments.CapturesRefundRequest;
import com.paypal.payments.Money;
import com.paypal.payments.Refund;
import com.paypal.payments.RefundRequest;
import lombok.extern.slf4j.Slf4j;
import org.chen.common.constants.Constants;
import org.chen.common.model.order.AbnormalPaymentRecord;
import org.chen.common.model.travel.StoreTravelOrder;
import org.chen.common.utils.DateUtil;
import org.chen.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;

@Service
@Slf4j
public class AsyncTaskServiceImpl implements AsyncTaskService {

    @Resource
    private PayPalHttpClient payPalHttpClient;

    @Autowired
    private StoreTravelOrderService storeTravelOrderService;

    @Autowired
    private StoreOrderStatusService storeOrderStatusService;


    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private  AbnormalPaymentRecordService abnormalPaymentRecordService;

    @Autowired
    private AlertService alertService;

    @Async
    public void processPaymentAsync(StoreTravelOrder order) {
        // 处理异步任务，如记录日志、发送通知等
        publishOrderGenerateLink(order);
    }

    @Override
    public void processRefund(StoreTravelOrder order) {
        try {
            String captureId = getCaptureIdFromOrder(order.getPayId());
            CapturesRefundRequest refundRequest = createRefundRequest(captureId, order.getPayPrice());

            HttpResponse<Refund> response = executeRefundRequest(refundRequest);
            com.paypal.payments.Refund refund = response.result();

            if ("COMPLETED".equals(refund.status())) {
                updateOrderAfterSuccessfulRefund(order);
            } else {
                handleFailedRefund(order, refund.status());
            }
        } catch (Exception e) {
            log.error("Error processing refund for order: " + order.getOrderId(), e);
            handleFailedRefund(order, "退款失败");
        }
    }

    @Override
    public void agreeRefund(StoreTravelOrder existStoreOrder) {
        publishOrderAgreeRefundEvent(existStoreOrder);
    }

    @Retryable(value = {IOException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
    private HttpResponse<com.paypal.payments.Refund> executeRefundRequest(CapturesRefundRequest refundRequest) throws IOException {
        return payPalHttpClient.execute(refundRequest);
    }

    private String getCaptureIdFromOrder(String payPalOrderId) throws IOException {
        OrdersGetRequest request = new OrdersGetRequest(payPalOrderId);
        Order payPalOrder = payPalHttpClient.execute(request).result();
        return payPalOrder.purchaseUnits().get(0).payments().captures().get(0).id();
    }

    private CapturesRefundRequest createRefundRequest(String captureId, BigDecimal amount) {
        CapturesRefundRequest refundRequest = new CapturesRefundRequest(captureId);
        RefundRequest refundRequestBody = new RefundRequest();
        Money money = new Money().currencyCode("THB").value(amount.toString());
        refundRequestBody.amount(money);
        refundRequest.requestBody(refundRequestBody);
        return refundRequest;
    }

    public void updateOrderAfterSuccessfulRefund(StoreTravelOrder order) {
        order.setRefundStatus(2); // 已退款
        order.setRefundPrice(order.getProTotalPrice());
        order.setRefundReasonTime(DateUtil.nowDateTime());
        boolean result = storeTravelOrderService.updateById(order);
        if (result) {
            publishOrderRefundTask(order);
            storeOrderStatusService.createTravelLog(order.getId(), Constants.ORDER_LOG_REFUND_SUCCESS, "PayPal退款成功");
        } else {
            log.error("Failed to update order status after successful refund: {},{}", order.getOrderId(),order.getId());
            throw new RuntimeException("Failed to update order status after successful refund");
        }
    }

    private void handleFailedRefund(StoreTravelOrder order, String status) {
        log.error("Refund failed for order: {}. Status: {}", order.getOrderId(), status);
        order.setRefundStatus(4); // 退款失败
        boolean result = storeTravelOrderService.updateById(order);
        if (result) {
            storeOrderStatusService.createTravelLog(order.getId(), Constants.ORDER_LOG_REFUND_FAILED, "PayPal退款失败: " + status);
            notifyUsersAboutRefund(order);
        } else {
            log.error("Failed to update order status after failed refund: {}", order.getOrderId());
            throw new RuntimeException("Failed to update order status after failed refund");
        }
    }

    private void notifyUsersAboutRefund(StoreTravelOrder order) {
        try {
            alertService.sendOrderRefundFailureNotice(order.getEmail(),order.getOrderId(),order.getRealName());
        } catch (Exception e) {
            log.error("Failed to send refund notification email to admin: {}", order.getEmail(), e);
        }
    }

    @Async
    public void processSuccessfulPayment(StoreTravelOrder order) {
        try {
            publishOrderPaySuccessTask(order);
            // 可以添加其他异步操作，如发送确认邮件
            publishOrderCreatedEvent(order);
        } catch (Exception e) {
            log.error("Error in async processing of successful payment for order: " + order.getOrderId(), e);
            // 考虑实现重试机制或警报系统
        }
    }

    private void publishOrderPaySuccessTask(StoreTravelOrder storeOrder) {
        try {
            kafkaTemplate.send("order-pay-success-task", objectMapper.writeValueAsString(storeOrder.getId()));
        } catch (JsonProcessingException e) {
            log.error("Failed to publish order refund event", e);
        }
    }

    private void publishOrderGenerateLink(StoreTravelOrder storeOrder) {
        try {
            kafkaTemplate.send("order-generate-link", objectMapper.writeValueAsString(storeOrder.getId()));
        } catch (JsonProcessingException e) {
            log.error("Failed to publish order refund event", e);
        }
    }

    /**
     * 发kafka消息,通知记录订单数或者通知用户以及其他操作*
     *
     * @param storeOrder 订单对象
     */
    private void publishOrderCreatedEvent(StoreTravelOrder storeOrder) {
        try {
            String orderJson = objectMapper.writeValueAsString(storeOrder);
            kafkaTemplate.send("order-payed", orderJson);
        } catch (JsonProcessingException e) {
            log.error("Failed to publish order created event", e);
        }
    }

    private void publishOrderAgreeRefundEvent(StoreTravelOrder storeOrder) {
        try {
            String orderJson = objectMapper.writeValueAsString(storeOrder);
            kafkaTemplate.send("order-agree-refund", orderJson);
        } catch (JsonProcessingException e) {
            log.error("Failed to publish order created event", e);
        }
    }

    private void publishOrderRefundTask(StoreTravelOrder storeOrder) {
        try {
            kafkaTemplate.send("order-refund-task", objectMapper.writeValueAsString(storeOrder.getId()));
        } catch (JsonProcessingException e) {
            log.error("Failed to publish order refund task", e);
        }
    }

    /**
     * 订单不存在时自动退款
     */
    @Async
    @Override
    public void autoRefundForNonExistentOrder(String payPalOrderId, BigDecimal amount) {
        try {
            log.info("开始执行自动退款（订单不存在），PayPal订单号：{}", payPalOrderId);

            // 执行退款
            boolean success = executePayPalRefund(payPalOrderId, amount);

            // 更新记录状态
            updateRefundRecordStatus(payPalOrderId,
                    success ? "SUCCESS" : "FAILED");

            if (success) {
                log.info("自动退款成功（订单不存在），PayPal订单号：{}", payPalOrderId);
            } else {
                log.error("自动退款失败（订单不存在），PayPal订单号：{}", payPalOrderId);
                alertService.sendAlert("自动退款失败",
                        String.format("PayPal订单号：%s，原因：订单不存在", payPalOrderId));
            }

        } catch (Exception e) {
            log.error("自动退款异常（订单不存在），PayPal订单号：{}", payPalOrderId, e);
            updateRefundRecordStatus(payPalOrderId, "FAILED");
            alertService.sendAlert("自动退款异常",
                    String.format("PayPal订单号：%s，异常：%s", payPalOrderId, e.getMessage()));
        }
    }

    /**
     * 重复支付时自动退款
     */
    @Async
    @Override
    public void autoRefundForDuplicatePayment(StoreTravelOrder order,
                                              String payPalOrderId,
                                              BigDecimal amount) {
        try {
            log.info("开始执行自动退款（重复支付），订单号：{}，PayPal订单号：{}",
                    order.getOrderId(), payPalOrderId);

            boolean success = executePayPalRefund(payPalOrderId, amount);

            updateRefundRecordStatus(payPalOrderId,
                    success ? "SUCCESS" : "FAILED");

            // 记录到订单日志
            storeOrderStatusService.createTravelLog(
                    order.getId(),
                    "auto_refund_duplicate",
                    String.format("检测到重复支付，已自动退款，金额：%s", amount)
            );

            if (!success) {
                alertService.sendAlert("自动退款失败",
                        String.format("订单号：%s，PayPal订单号：%s，原因：重复支付",
                                order.getOrderId(), payPalOrderId));
            }

        } catch (Exception e) {
            log.error("自动退款异常（重复支付），订单号：{}", order.getOrderId(), e);
            alertService.sendAlert("自动退款异常",
                    String.format("订单号：%s，异常：%s", order.getOrderId(), e.getMessage()));
        }
    }

    /**
     * 金额不匹配时自动退款
     */
    @Async
    @Override
    public void autoRefundForAmountMismatch(StoreTravelOrder order,
                                            String payPalOrderId,
                                            BigDecimal amount) {
        try {
            log.info("开始执行自动退款（金额不匹配），订单号：{}，订单金额：{}，实际支付：{}",
                    order.getOrderId(), order.getPayPrice(), amount);

            boolean success = executePayPalRefund(payPalOrderId, amount);

            updateRefundRecordStatus(payPalOrderId,
                    success ? "SUCCESS" : "FAILED");

            if (!success) {
                alertService.sendAlert("自动退款失败",
                        String.format("订单号：%s，原因：金额不匹配，订单金额：%s，实际支付：%s",
                                order.getOrderId(), order.getPayPrice(), amount));
            }

        } catch (Exception e) {
            log.error("自动退款异常（金额不匹配），订单号：{}", order.getOrderId(), e);
        }
    }

    /**
     * 订单已取消且不可恢复时自动退款
     */
    @Async
    @Override
    public void autoRefundForCancelledOrder(StoreTravelOrder order,
                                            String payPalOrderId,
                                            BigDecimal amount) {
        try {
            log.info("开始执行自动退款（订单已取消），订单号：{}", order.getOrderId());

            boolean success = executePayPalRefund(payPalOrderId, amount);

            updateRefundRecordStatus(payPalOrderId,
                    success ? "SUCCESS" : "FAILED");

            // 记录到订单日志
            storeOrderStatusService.createTravelLog(
                    order.getId(),
                    "auto_refund_cancelled",
                    "订单已取消且不可恢复，已自动退款"
            );

        } catch (Exception e) {
            log.error("自动退款异常（订单已取消），订单号：{}", order.getOrderId(), e);
        }
    }

    /**
     * 订单已退款，不能再次支付
     */
    @Async
    @Override
    public void autoRefundForRefundedOrder(StoreTravelOrder order,
                                            String payPalOrderId,
                                            BigDecimal amount) {
        try {
            log.info("开始执行自动退款（订单已退款，不能再次支付），订单号：{}", order.getOrderId());

            boolean success = executePayPalRefund(payPalOrderId, amount);

            updateRefundRecordStatus(payPalOrderId,
                    success ? "SUCCESS" : "FAILED");

            // 记录到订单日志
            storeOrderStatusService.createTravelLog(
                    order.getId(),
                    "auto_refund_cancelled",
                    "订单已退款，不能再次支付"
            );

        } catch (Exception e) {
            log.error("自动退款异常（订单已退款，不能再次支付），订单号：{}", order.getOrderId(), e);
        }
    }

    /**
     * 订单恢复失败时自动退款
     */
    @Async
    @Override
    public void autoRefundForRecoveryFailed(StoreTravelOrder order,
                                            String payPalOrderId,
                                            BigDecimal amount) {
        try {
            log.info("开始执行自动退款（订单恢复失败），订单号：{}", order.getOrderId());

            boolean success = executePayPalRefund(payPalOrderId, amount);

            updateRefundRecordStatus(payPalOrderId,
                    success ? "SUCCESS" : "FAILED");

            // 记录到订单日志
            storeOrderStatusService.createTravelLog(
                    order.getId(),
                    "auto_refund_cancelled",
                    "订单恢复失败，已自动退款"
            );

        } catch (Exception e) {
            log.error("自动退款异常（订单恢复失败），订单号：{}", order.getOrderId(), e);
        }
    }

    /**
     * 执行 PayPal 退款
     */
    @Retryable(value = {IOException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000))
    private boolean executePayPalRefund(String payPalOrderId, BigDecimal amount) throws IOException {
        try {
            // 1️⃣ 获取 Capture ID
            String captureId = getCaptureIdFromOrder(payPalOrderId);

            // 2️⃣ 创建退款请求
            CapturesRefundRequest refundRequest = new CapturesRefundRequest(captureId);
            RefundRequest refundRequestBody = new RefundRequest();
            Money money = new Money().currencyCode("THB").value(amount.toString());
            refundRequestBody.amount(money);
            refundRequest.requestBody(refundRequestBody);

            // 3️⃣ 执行退款
            HttpResponse<Refund> response = payPalHttpClient.execute(refundRequest);
            Refund refund = response.result();

            // 4️⃣ 检查退款状态
            boolean success = "COMPLETED".equals(refund.status());

            log.info("PayPal退款结果，订单号：{}，状态：{}，退款ID：{}",
                    payPalOrderId, refund.status(), refund.id());

            return success;

        } catch (Exception e) {
            log.error("PayPal退款失败，订单号：{}", payPalOrderId, e);
            throw e;
        }
    }

    /**
     * 更新退款记录状态
     */
    private void updateRefundRecordStatus(String payPalOrderId, String status) {
        try {
            AbnormalPaymentRecord record = abnormalPaymentRecordService
                    .getByPayPalOrderId(payPalOrderId);

            if (record != null) {
                record.setStatus(status);
                record.setUpdateTime(new Date());
                abnormalPaymentRecordService.updateById(record);
            }
        } catch (Exception e) {
            log.error("更新退款记录状态失败，PayPal订单号：{}", payPalOrderId, e);
        }
    }
}
